<template>
  <div class="sandbox">
    <input type="range" min="0" max="100" v-model="param" @input="drawSimulation" />
    <svg ref="svgRef" :width="width" :height="height"></svg>
  </div>
</template>
<script setup lang="ts">

import { ref, onMounted, watch } from 'vue';
import * as d3 from 'd3';

const width=600, height=300;
const svgRef=ref<SVGSVGElement|null>(null);
const param=ref(50);

function drawSimulation(){
  if(!svgRef.value) return;
  const svg = d3.select(svgRef.value);
  svg.selectAll('*').remove();
  const data = d3.range(20).map(()=>({x:Math.random()*width,y:Math.random()*height}));
  const simulation = d3.forceSimulation(data as any)
    .force('charge',d3.forceManyBody().strength(param.value - 50))
    .force('center',d3.forceCenter(width/2,height/2))
    .force('collision',d3.forceCollide(20))
    .on('tick',()=>{
      const u=svg.selectAll('circle').data(data);
      u.join('circle')
        .attr('cx',(d:any)=>d.x).attr('cy',(d:any)=>d.y)
        .attr('r',10).attr('fill','steelblue');
    });
}

onMounted(()=>drawSimulation());
watch(param,()=>drawSimulation());
</script>
<style scoped>.sandbox{display:flex;flex-direction:column;height:100%;padding:10px;}input{margin-bottom:10px;}svg{flex:1;}</style>